#!/usr/bin/env python
# coding=utf-8

#####################################################
# ghtoc   : markdown folder toc generator
# Author  : sinlov <sinlovgmppt@gmail.com>
# Usage   : toc.py <markdown file>
# Date    : 2016-10-24
# License : see https://github.com/sinlov/markdown-folder-toc
# Copyright (C) 2016 sinlov
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
import os
import re
import sys
import optparse

__author__ = 'sinlov'

is_verbose = False
top_level = 77
folder_deep = 5

save_file_name = 'preface.md'
toc_file_name = 'SUMMARY.MD'

lnk_temp = '%s- [%s](%s#%s)'
path_lnk_temp = '[%s](%s)'
TOC_MARK = '--------------'
REG_TOC_MARK = r'--------------'
REF = '**Folder TOC generated by [sinlov](https://github.com/sinlov/markdown-folder-toc)**'

hint_help_info = """
Thanks use Markdown Folder TOC generate
more information see https://github.com/sinlov/markdown-folder-toc
"""

error_info = """
Your input error
    Usage:
        ./folder_toc.py <markdown folder>
    or input [-h] to see help
"""


# def get_cur_dir():
#     global __CUR_DIR
#     ret_path = __CUR_DIR
#     if sys.platform.system() == 'Windows':
#         ret_path = ret_path.decode('gbk')
#     return ret_path
#     caller_file = inspect.stack()[0][1]
#     ret_path = os.path.abspath(os.path.dirname(caller_file))
#     if platform.system() == 'Windows':
#         ret_path = ret_path.decode('gbk')
#     return ret_path


# def get_full_path(filename):
#     filename = filename.replace('\\', '/')
#     # filename = re.sub('/+', '/', filename)
#     if os.path.isabs(filename):
#         return filename
#     dir_name = get_cur_dir()
#     filename = os.path.join(dir_name, filename)
#     filename = filename.replace('\\', '/')
#     filename = re.sub('/+', '/', filename)
#     return filename


def print_cli_by_is_verbose(msg=str):
    if is_verbose:
        print msg


def auto_move_toc(full):
    result = []
    not_toc = True
    for line in full:
        if re.match(REG_TOC_MARK, line):
            not_toc = not not_toc
            continue
        elif not_toc:
            result.append(line)
    return result


def tr_toc(header, file_name=str):
    global lnk_temp
    lvl, txt = re.findall(r'^(\d+) (.*)', header)[0]
    return lnk_temp % ((int(lvl) - top_level) * '    ', txt, file_name,
                       re.sub(' ', '-', re.sub(u'[^[\u4e00-\u9fa5_a-zA-Z0-9]+$]', '', txt.lower())))


def generate_file_toc(root=str, root_len=int, f_name=str, save_name=str):
    global top_level
    lines = []
    with open(os.path.join(root, f_name), 'r') as md_file:
        lines = md_file.readlines()
        if len(lines) == 0:
            print 'You file is empty, please check it!'
            return
    newlines = auto_move_toc(lines)
    # remove ``` ``` for line code
    code_mark_count = 0
    filter_lines = []
    for new_line in newlines:
        if re.match(r'(```)+', new_line):
            code_mark_count += 1
        if re.match(r'#+', new_line) and code_mark_count % 2 == 0:
            filter_lines.append(new_line)
    file_toc = [e.strip() for e in filter_lines if re.match(r'#+', e)]

    # encode TOC
    for i, h in enumerate(file_toc):
        ln = len(re.search(r'^#+', h).group(0))
        top_level = ln if ln < top_level else top_level
        file_toc[i] = re.sub(r'^#+\s*', str(ln) + ' ', h)
    md_path = ''
    if root[root_len:]:
        md_path = root[root_len:] + '/' + f_name
    else:
        md_path = f_name
    file_toc = [tr_toc(h, md_path) for h in file_toc]
    # write in file
    with open(save_name, 'a') as f:
        file_line = path_lnk_temp % (md_path[:-3], md_path)
        # print_cli_by_is_verbose('write file line: %s' % file_line)
        f.write('\n' + file_line + '\n\n')
        f.write('\n'.join(file_toc) + '\n')
        # f.write(''.join(newlines))
        f.write('\n')


def generate_markdown_folder(root_path=str):
    global folder_deep
    if os.path.exists(save_path):
        os.remove(save_path)
    print "=== Save path ===\nas: " + save_path + '\n'
    if folder_deep != 5:
        print 'folder level change as: ' + str(folder_deep) + '\n'
    now_folder_deep = 1
    root_len = len(root_path)
    for root, dirs, files in os.walk(top=folder_path, topdown=True, followlinks=False):
        s_files = sorted(files)
        for name in s_files:
            abs_name = str(name)
            low_name = name.lower()
            upper_name = name.upper()
            if low_name.endswith(".md") and folder_deep >= now_folder_deep:
                if name.upper().endswith('README.MD'):
                    print_cli_by_is_verbose("Find toc README file at: " + os.path.join(root, abs_name) + ' Pass generate!')
                else:
                    if upper_name.endswith(toc_file_name):
                        print_cli_by_is_verbose(
                            "Find toc markdown file at: " + os.path.join(root, abs_name) + ' Pass generate!')
                    else:
                        print_cli_by_is_verbose("Find markdown file at: " + os.path.join(root, abs_name))
                        generate_file_toc(root, root_len, abs_name, save_path)

        for name in dirs:
            now_folder_deep += 1
            # print  'folder_deep: ' + str(folder_deep) + ' |now_folder_deep ' + str(now_folder_deep)
    with open(save_path, 'a') as f:
        f.write('\n' + TOC_MARK)
        f.write('\n\n\n')
        f.write(REF)
        f.write('\n\n')


if __name__ == '__main__':
    folder_path = ''
    if len(sys.argv) < 2:
        print error_info
        exit(1)
    parser = optparse.OptionParser('\n%prog ' + '-p \n\tOr %prog <folder>\n' + hint_help_info)
    parser.add_option('-v', dest='v_verbose', action="store_true", help="see verbose", default=False)
    parser.add_option('-p', '--pwd', dest='p_pwd', action="store_true",
                      help="start pwd folder", default=False)
    parser.add_option('-f', '--folder', dest='f_folder', type="string", help="path of folder Default is .",
                      default=".", metavar=".")
    parser.add_option('-d', '--deep', dest='d_deep', type="int", help="folder deep Default 5",
                      default=5, metavar=5)
    parser.add_option('-l', '--level', dest='l_level', type="int", help="top level Default 77",
                      default=77, metavar=77)
    (options, args) = parser.parse_args()
    if options.v_verbose:
        is_verbose = True
    if options.p_pwd:
        folder_path = os.getcwd()
    if options.d_deep is not None:
        folder_deep = options.d_deep
    if options.l_level is not None:
        top_level = options.l_level
    if options.f_folder is not None:
        folder_path = options.f_folder
    # check args finish
    if not os.path.exists(folder_path):
        print "Your input Folder is not exist " + folder_path
        exit(-1)
    if os.path.isdir(folder_path) < 1:
        print "You input " + folder_path + "is not folder"
        exit(-2)
    # check folder path finish
    print 'You want generate path \n\tat: ' + str(folder_path)
    save_path = os.path.realpath(folder_path) + "/" + save_file_name
    generate_markdown_folder(folder_path)
    print '=== folder generate success! ===\nSee at ' + save_path
